<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>boost meta state machine - lclei blog</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="lclei" /><meta name="description" content="MSM Meta State Machine，是boost库的元状态机，使用了大量的模板元编程，让使用者轻松创建出好用，可阅读，效率高的状态机。它的特点是使用状态转" /><meta name="keywords" content="lclei, blog, code" />






<meta name="generator" content="Hugo 0.68.3 with theme even" />


<link rel="canonical" href="http://localhost:1313/post/msm/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.2e81bbed97b8b282c1aeb57488cc71c8d8c8ec559f3931531bd396bf31e0d4dd.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="boost meta state machine" />
<meta property="og:description" content="MSM Meta State Machine，是boost库的元状态机，使用了大量的模板元编程，让使用者轻松创建出好用，可阅读，效率高的状态机。它的特点是使用状态转" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://localhost:1313/post/msm/" />
<meta property="article:published_time" content="2022-07-10T00:00:00+00:00" />
<meta property="article:modified_time" content="2022-07-10T00:00:00+00:00" />
<meta itemprop="name" content="boost meta state machine">
<meta itemprop="description" content="MSM Meta State Machine，是boost库的元状态机，使用了大量的模板元编程，让使用者轻松创建出好用，可阅读，效率高的状态机。它的特点是使用状态转">
<meta itemprop="datePublished" content="2022-07-10T00:00:00&#43;00:00" />
<meta itemprop="dateModified" content="2022-07-10T00:00:00&#43;00:00" />
<meta itemprop="wordCount" content="3535">



<meta itemprop="keywords" content="cpp,boost," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="boost meta state machine"/>
<meta name="twitter:description" content="MSM Meta State Machine，是boost库的元状态机，使用了大量的模板元编程，让使用者轻松创建出好用，可阅读，效率高的状态机。它的特点是使用状态转"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">lclei</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">Home</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">Archives</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">Tags</li>
      </a><a href="/categories/">
        <li class="mobile-menu-item">Categories</li>
      </a><a href="/about/">
        <li class="mobile-menu-item">About</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">lclei</a>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">Home</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">Archives</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">Tags</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/categories/">Categories</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/">About</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">boost meta state machine</h1>

      <div class="post-meta">
        <span class="post-time"> 2022-07-10 </span>
        
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">Contents</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#从一个简单的状态机开始">从一个简单的状态机开始</a></li>
        <li><a href="#state">State</a></li>
        <li><a href="#action">Action</a></li>
        <li><a href="#guard">Guard</a></li>
        <li><a href="#transition_table">transition_table</a></li>
        <li><a href="#if-else">if-else</a></li>
        <li><a href="#状态自转移">状态自转移</a></li>
        <li><a href="#exception">exception</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>MSM Meta State Machine，是boost库的元状态机，使用了大量的模板元编程，让使用者轻松创建出好用，可阅读，效率高的状态机。它的特点是使用状态转移表 transition_table 来定义状态机转移的过程，非常直观，易于阅读，修改，排错和修改。状态转移表的要素是源状态 Sourcce State，目标状态 Target State，触发事件Event，守卫条件Guard和执行动作Action。</p>
<p>本文代码示例在<a href="https://gitee.com/lclei/boost_msm_guide">boost_msm_guide</a></p>
<h2 id="从一个简单的状态机开始">从一个简单的状态机开始</h2>
<p>使用boost msm定义一个简单的状态机分为6步：</p>
<ol>
<li>定义事件Event</li>
<li>定义状态机front-end <code>boost::msm::front::state_machine_def</code></li>
<li>定义状态</li>
<li>设置初始状态</li>
<li>定义状态转移表</li>
<li>生成状态机back-end</li>
</ol>
<p>状态机使用时</p>
<ol>
<li>定义状态机实例fsm</li>
<li>开始状态机fsm.start()</li>
<li>处理事件fsm.process_event()</li>
</ol>
<p>首先从一个只有状态转移的简单状态机开始</p>
<p><img src="//www.plantuml.com/plantuml/png/SoWkIImgAStDuL8ioKZDJLKeo4dCpEC2YfQaAWI3I4C5AuNClCoIpCISUB0mLD8rBmKeKv9Qb9kP1vU2wj2rWqgxbgNcbHXoEQJcfG3j0000" alt=""></p>
<p>代码如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="cp">#include</span> <span class="cpf">&lt;boost/msm/back/state_machine.hpp&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;boost/msm/front/state_machine_def.hpp&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;boost/msm/front/functor_row.hpp&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="cp"></span>
<span class="k">namespace</span> <span class="p">{</span>
    <span class="c1">// ---Events
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">Event1</span> <span class="p">{};</span>

    <span class="c1">// ---State Machine front-end
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">Sm</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">state_machine_def</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span>
    <span class="p">{</span>
        <span class="c1">// States
</span><span class="c1"></span>        <span class="k">struct</span> <span class="nc">State1</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">state</span><span class="o">&lt;&gt;</span> <span class="p">{</span>
            <span class="c1">// Entry Action
</span><span class="c1"></span>            <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
            <span class="kt">void</span> <span class="n">on_entry</span><span class="p">(</span><span class="n">Event</span> <span class="k">const</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">Fsm</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Entering State1</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="c1">// Exit Action
</span><span class="c1"></span>            <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
            <span class="kt">void</span> <span class="n">on_exit</span><span class="p">(</span><span class="n">Event</span> <span class="k">const</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">Fsm</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Leaving State1</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">};</span>

        <span class="k">struct</span> <span class="nc">End</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">terminate_state</span><span class="o">&lt;&gt;</span> <span class="p">{};</span>

        <span class="c1">// Set initial state
</span><span class="c1"></span>        <span class="k">using</span> <span class="n">initial_state</span> <span class="o">=</span> <span class="n">State1</span><span class="p">;</span>

        <span class="c1">// Transition Table
</span><span class="c1"></span>        <span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
            <span class="c1">//    Start | Event | Next | Action | Guard
</span><span class="c1"></span>            <span class="n">_row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event1</span><span class="p">,</span> <span class="n">End</span>                  <span class="o">&gt;</span>
        <span class="o">&gt;</span> <span class="p">{};</span>
    <span class="p">};</span>

    <span class="c1">// Pick a back-end
</span><span class="c1"></span>    <span class="k">using</span> <span class="n">Fsm</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="nl">msm</span><span class="p">:</span><span class="err">🔙</span><span class="o">:</span><span class="n">state_machine</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="kt">void</span> <span class="nf">test</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">Fsm</span> <span class="n">fsm</span><span class="p">;</span>
        <span class="n">fsm</span><span class="p">.</span><span class="n">start</span><span class="p">();</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;&gt; Send Event1</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
        <span class="n">fsm</span><span class="p">.</span><span class="n">process_event</span><span class="p">(</span><span class="n">Event1</span><span class="p">{});</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">test</span><span class="p">();</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>编译运行此状态，打印是</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">Entering State1
&gt; Send Event1
Leaving State1
</code></pre></td></tr></table>
</div>
</div><h2 id="state">State</h2>
<p>状态机的第一要素当然是状态，一个状态机的一生就是在各个状态间来来去去。状态间的迁移由Event事件触发，迁移中间可以执行Action，是否能迁移取决于Guard。每个状态带有on_entry和on_exit两个方法，顾名思义，在进入和离开时触发。</p>
<p>为了后续更好的演示，我们定义一个base class执行一些基础的打印。<br>
首先，获取type的名称。我们知道标准库中的<code>typeid(var).name()</code>方法可以获取到变量的类型名称，但是是内部的符号，我们可以通过boost::core::demangle方法来获取更易读的名称，同时把命名空间的前缀去掉。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">get_typename</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">core</span><span class="o">::</span><span class="n">demangle</span><span class="p">(</span><span class="k">typeid</span><span class="p">(</span><span class="n">x</span><span class="p">).</span><span class="n">name</span><span class="p">());</span>
    <span class="k">auto</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">name</span><span class="p">.</span><span class="n">rfind</span><span class="p">(</span><span class="s">&#34;::&#34;</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pos</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">::</span><span class="n">npos</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">name</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>BaseState负责在on_entry和on_exit时打印日志，这两个方法由状态机在进入和离开状态时自动调用。为了继承的子类可以定制一些动作，定义了虚函数prepare和clean，参数为状态机内的ctx。实际上，这里和on_entry一样传入template Event和Fsm参数更好，但是由于c++语言的限制，模板函数不能为虚函数，所以退而求其次，传入一个新的Context变量。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">struct</span> <span class="nc">BaseState</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">state</span><span class="o">&lt;&gt;</span> <span class="p">{</span>
    <span class="k">virtual</span> <span class="o">~</span><span class="n">BaseState</span><span class="p">()</span> <span class="p">{}</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
    <span class="kt">void</span> <span class="n">on_entry</span><span class="p">(</span><span class="n">Event</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">event</span><span class="p">,</span> <span class="n">Fsm</span> <span class="o">&amp;</span><span class="n">fsm</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;[state]...Entering &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">)</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34; by &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
        <span class="n">prepare</span><span class="p">(</span><span class="n">fsm</span><span class="p">.</span><span class="n">ctx</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
    <span class="kt">void</span> <span class="n">on_exit</span><span class="p">(</span><span class="n">Event</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">event</span><span class="p">,</span> <span class="n">Fsm</span> <span class="o">&amp;</span><span class="n">fsm</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;[state]...Leaving &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">)</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34; by &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
        <span class="n">clean</span><span class="p">(</span><span class="n">fsm</span><span class="p">.</span><span class="n">ctx</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">prepare</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="p">{}</span>
    <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">clean</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><p>现在，我们的状态机得以精简</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp">    <span class="k">struct</span> <span class="nc">Sm</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">state_machine_def</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span>
    <span class="p">{</span>
    <span class="c1">// ---States
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">State1</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">End</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">terminate_state</span><span class="o">&lt;&gt;</span> <span class="p">{};</span>

    <span class="c1">// ---Set initial state
</span><span class="c1"></span>    <span class="k">using</span> <span class="n">initial_state</span> <span class="o">=</span> <span class="n">State1</span><span class="p">;</span>

    <span class="c1">// ---Transition Table
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
        <span class="c1">//    Start | Event | Next | Action | Guard
</span><span class="c1"></span>        <span class="n">_row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event1</span><span class="p">,</span> <span class="n">End</span>                  <span class="o">&gt;</span>
    <span class="o">&gt;</span> <span class="p">{};</span>

    <span class="n">Context</span> <span class="n">ctx</span><span class="p">;</span>
<span class="p">};</span>

<span class="c1">// ---Pick a back-end
</span><span class="c1"></span><span class="k">using</span> <span class="n">Fsm</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="nl">msm</span><span class="p">:</span><span class="err">🔙</span><span class="o">:</span><span class="n">state_machine</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></td></tr></table>
</div>
</div><p>打印是</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">[state]...Entering State1 by InitEvent
&gt; Send Event1
[state]...Leaving State1 by Event1
</code></pre></td></tr></table>
</div>
</div><p>值得注意的是InitEvent，它是从哪来的？我们的transition_table并没有定义这个事件！实际上，这是Fsm进入initial_state的默认触发事件。</p>
<h2 id="action">Action</h2>
<p>Action发生在离开状态后，进入下一状态前。可以使用一个Functor class来表示。和State一样，这里定义一个BaseAction的类。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">struct</span> <span class="nc">BaseAction</span> <span class="p">{</span>
    <span class="k">virtual</span> <span class="o">~</span><span class="n">BaseAction</span><span class="p">()</span> <span class="p">{}</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="p">,</span> <span class="k">class</span> <span class="nc">SourceState</span><span class="p">,</span> <span class="k">class</span> <span class="nc">TargetState</span><span class="o">&gt;</span>
    <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">Event</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">event</span><span class="p">,</span> <span class="n">Fsm</span> <span class="o">&amp;</span><span class="n">fsm</span><span class="p">,</span> <span class="n">SourceState</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">from</span><span class="p">,</span> <span class="n">TargetState</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">to</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&gt;&gt;</span> <span class="s">&#34;[action] Do &#34;</span> <span class="o">&gt;&gt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="s">&#34; from &#34;</span> <span class="o">&gt;&gt;</span>
                <span class="o">&gt;&gt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="s">&#34; to &#34;</span> <span class="o">&gt;&gt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">to</span><span class="p">)</span> <span class="o">&gt;&gt;</span>
                <span class="o">&gt;&gt;</span> <span class="s">&#34; by &#34;</span> <span class="o">&gt;&gt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
        <span class="n">execute</span><span class="p">(</span><span class="n">fsm</span><span class="p">.</span><span class="n">ctx</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="guard">Guard</h2>
<p>Guard发生在离开状态前，返回一个bool值，如果为true，则可以转移，否则保持在原状态。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">struct</span> <span class="nc">BaseGuard</span> <span class="p">{</span>
    <span class="k">virtual</span> <span class="o">~</span><span class="n">BaseGuard</span><span class="p">()</span> <span class="p">{}</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="p">,</span> <span class="k">class</span> <span class="nc">SourceState</span><span class="p">,</span> <span class="k">class</span> <span class="nc">TargetState</span><span class="o">&gt;</span>
    <span class="kt">bool</span> <span class="k">operator</span><span class="p">()(</span><span class="n">Event</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">event</span><span class="p">,</span> <span class="n">Fsm</span> <span class="o">&amp;</span><span class="n">fsm</span><span class="p">,</span> <span class="n">SourceState</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">from</span><span class="p">,</span> <span class="n">TargetState</span> <span class="k">const</span> <span class="o">&amp;</span><span class="n">to</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">bool</span> <span class="n">ok</span> <span class="o">=</span> <span class="n">execute</span><span class="p">(</span><span class="n">fsm</span><span class="p">.</span><span class="n">ctx</span><span class="p">);</span>
        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;[guard] &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; -&gt; &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span> <span class="o">&lt;&lt;</span> <span class="n">ok</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34; from &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">from</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; to &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">to</span><span class="p">)</span>
                <span class="o">&lt;&lt;</span> <span class="s">&#34; by &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">ok</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">virtual</span> <span class="kt">bool</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="nb">true</span><span class="p">;}</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="transition_table">transition_table</h2>
<p>状态转移表的完整形态是5个元素：
fromState， Event， ToState， Action， Guard
一般使用functor_row里的boost::msm::front::Row来定义转移表的每一行。其中空的要素使用boost::msm::front::none来表示。
可以使用using来简化这个两个类型</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="k">using</span> <span class="n">Row</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">Row</span><span class="o">&lt;</span><span class="n">T</span><span class="p">...</span><span class="o">&gt;</span><span class="p">;</span>

<span class="k">using</span> <span class="n">None</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">none</span><span class="p">;</span>
</code></pre></td></tr></table>
</div>
</div><p>至此我们可以写一个完整的状态了。</p>
<p><img src="//www.plantuml.com/plantuml/png/JOoz2a8n38NtFaLz095cT93hS15dHn4fDc2WYL9JdzzOexWad9_lJ0_DJJlNiD0hCiPxpIJ1NCMu5zAuZcIFSZqFqwF3-wP_0IvcASOeDYOnxTIOMcw-tEVz333YkEkvbNIQdoYQLjkBqasy2TRquH63nn0cbDAvlW00" alt=""></p>
<p>代码为</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="c1">// ---State Machine front-end
</span><span class="c1"></span><span class="k">struct</span> <span class="nc">Sm</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">state_machine_def</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span>
<span class="p">{</span>
    <span class="c1">// ---States
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">State1</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">State2</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">Init</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">End</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">terminate_state</span><span class="o">&lt;&gt;</span> <span class="p">{};</span>

    <span class="c1">// ---Events
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">Event1</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">Event2</span> <span class="p">{};</span>

    <span class="c1">// ---Actions
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">Action1</span> <span class="o">:</span> <span class="n">BaseAction</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">Action2</span> <span class="o">:</span> <span class="n">BaseAction</span> <span class="p">{};</span>

    <span class="c1">// ---Guard
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">Guard1</span> <span class="o">:</span> <span class="n">BaseGuard</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">GTrue</span> <span class="o">:</span> <span class="n">BaseGuard</span> <span class="p">{};</span>
    <span class="k">struct</span> <span class="nc">GFalse</span> <span class="o">:</span> <span class="n">BaseGuard</span> <span class="p">{</span>
        <span class="kt">bool</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="c1">// ---Set initial state
</span><span class="c1"></span>    <span class="k">using</span> <span class="n">initial_state</span> <span class="o">=</span> <span class="n">Init</span><span class="p">;</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">T</span><span class="o">&gt;</span>
    <span class="k">using</span> <span class="n">Row</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">Row</span><span class="o">&lt;</span><span class="n">T</span><span class="p">...</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">using</span> <span class="n">None</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">msm</span><span class="o">::</span><span class="n">front</span><span class="o">::</span><span class="n">none</span><span class="p">;</span>

    <span class="c1">// ---Transition Table
</span><span class="c1"></span>    <span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
        <span class="c1">//   Start * Event * Next  * Action * Guard
</span><span class="c1"></span>        <span class="n">Row</span><span class="o">&lt;</span> <span class="n">Init</span><span class="p">,</span>   <span class="n">None</span><span class="p">,</span>   <span class="n">State1</span><span class="p">,</span> <span class="n">None</span><span class="p">,</span>    <span class="n">None</span>   <span class="o">&gt;</span><span class="p">,</span>
        <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event1</span><span class="p">,</span> <span class="n">State2</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">Guard1</span> <span class="o">&gt;</span><span class="p">,</span>
        <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State2</span><span class="p">,</span> <span class="n">Event2</span><span class="p">,</span> <span class="n">End</span><span class="p">,</span>    <span class="n">Action2</span><span class="p">,</span> <span class="n">None</span>   <span class="o">&gt;</span>
    <span class="o">&gt;</span> <span class="p">{};</span>

    <span class="n">Context</span> <span class="n">ctx</span><span class="p">;</span>
<span class="p">};</span>

<span class="c1">// ---Pick a back-end
</span><span class="c1"></span><span class="k">using</span> <span class="n">Fsm</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="nl">msm</span><span class="p">:</span><span class="err">🔙</span><span class="o">:</span><span class="n">state_machine</span><span class="o">&lt;</span><span class="n">Sm</span><span class="o">&gt;</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">test</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">Fsm</span> <span class="n">fsm</span><span class="p">;</span>
    <span class="n">fsm</span><span class="p">.</span><span class="n">start</span><span class="p">();</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;&gt; Send Event1</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
    <span class="n">fsm</span><span class="p">.</span><span class="n">process_event</span><span class="p">(</span><span class="n">Event1</span><span class="p">{});</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;&gt; Send Event2</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
    <span class="n">fsm</span><span class="p">.</span><span class="n">process_event</span><span class="p">(</span><span class="n">Event2</span><span class="p">{});</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>输出为</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">[state]...Entering Init by InitEvent
[state]...Leaving Init by none
[state]...Entering State1 by none
&gt; Send Event1
[guard] Guard1 -&gt; true from State1 to State2 by Event1
[state]...Leaving State1 by Event1
[action] Do Action1 from State1 to State2 by Event1
[state]...Entering State2 by Event1
&gt; Send Event2
[state]...Leaving State2 by Event2
[action] Do Action2 from State2 to End by Event2
</code></pre></td></tr></table>
</div>
</div><h2 id="if-else">if-else</h2>
<p>在transition_table中，在下方的row优先于上方的row先执行。<br>
这一节通过实现一个if-else的逻辑来说明在transition_table里row的优先级。</p>
<p><img src="//www.plantuml.com/plantuml/png/TO-n3e8m48RtFiNv09MKqGI20mCpYOjnQF28JOwJo45yV0yvJHnScdv_lylVgoQ93va7SZkvuO0mKapiD1M4TZs3GTE_qQYc2JTkE0buNveD1wWNP0bPYtAA5Fu9kGcvizmJzgAQ5QbtJZrqyjmlaQ0e85ooOoVfpk4xKjf7DX_rxZxZVXxrUIrtvlo65V9Lztu1" alt=""></p>
<p>两个Action</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="c1">// ---Actions
</span><span class="c1"></span><span class="k">struct</span> <span class="nc">SetVal1</span> <span class="o">:</span> <span class="n">BaseAction</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="n">ctx</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">ctx</span><span class="p">.</span><span class="n">val</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">SetVal2</span> <span class="o">:</span> <span class="n">BaseAction</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="n">ctx</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">ctx</span><span class="p">.</span><span class="n">val</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><p>Guard</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"> <span class="k">struct</span> <span class="nc">IfGuard</span> <span class="o">:</span> <span class="n">BaseGuard</span> <span class="p">{</span>
    <span class="kt">bool</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="n">ctx</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">ctx</span><span class="p">.</span><span class="n">val</span> <span class="o">==</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></td></tr></table>
</div>
</div><p>transition_table</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"> <span class="c1">// ---Transition Table
</span><span class="c1"></span><span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
    <span class="c1">//   Start * Event * Next  * Action * Guard
</span><span class="c1"></span>    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">Init</span>   <span class="p">,</span> <span class="n">Event1</span>    <span class="p">,</span> <span class="n">State1</span>    <span class="p">,</span> <span class="n">SetVal1</span>   <span class="p">,</span> <span class="n">None</span>  <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">Init</span>   <span class="p">,</span> <span class="n">Event2</span>    <span class="p">,</span> <span class="n">State1</span>    <span class="p">,</span> <span class="n">SetVal2</span>   <span class="p">,</span> <span class="n">None</span>  <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span> <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">ElseState</span> <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">None</span>  <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span> <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">IfState</span>   <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">IfGuard</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">IfState</span><span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">Init</span>      <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">None</span>  <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">ElseState</span><span class="p">,</span> <span class="n">None</span>    <span class="p">,</span> <span class="n">Init</span>      <span class="p">,</span> <span class="n">None</span>      <span class="p">,</span> <span class="n">None</span>  <span class="o">&gt;</span>
<span class="o">&gt;</span> <span class="p">{};</span>
</code></pre></td></tr></table>
</div>
</div><p>输出为</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">[state]...Entering Init by InitEvent
&gt; Send Event1
[state]...Leaving Init by Event1
[action] Do SetVal1 from Init to State1 by Event1
[state]...Entering State1 by Event1
[guard] IfGuard -&gt; true from State1 to IfState by none
[state]...Leaving State1 by none
[state]...Entering IfState by none
[state]...Leaving IfState by none
[state]...Entering Init by none
&gt; Send Event2
[state]...Leaving Init by Event2
[action] Do SetVal2 from Init to State1 by Event2
[state]...Entering State1 by Event2
[guard] IfGuard -&gt; false from State1 to IfState by none
[state]...Leaving State1 by none
[state]...Entering ElseState by none
[state]...Leaving ElseState by none
[state]...Entering Init by none
</code></pre></td></tr></table>
</div>
</div><h2 id="状态自转移">状态自转移</h2>
<p>转移到自己本身有两种方式，可以称为外部自转移和内部自转移。如</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="c1">// ---Transition Table
</span><span class="c1"></span><span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
    <span class="c1">//   Start * Event * Next  * Action * Guard
</span><span class="c1"></span>    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">Init</span><span class="p">,</span>   <span class="n">None</span><span class="p">,</span>   <span class="n">State1</span><span class="p">,</span> <span class="n">None</span><span class="p">,</span>    <span class="n">None</span>   <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event1</span><span class="p">,</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">Guard1</span> <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event2</span><span class="p">,</span> <span class="n">None</span>  <span class="p">,</span> <span class="n">Action2</span><span class="p">,</span> <span class="n">GTrue</span>  <span class="o">&gt;</span>
<span class="o">&gt;</span> <span class="p">{};</span>
</code></pre></td></tr></table>
</div>
</div><ol>
<li>start和next都是State1，此时会执行State1的on_exit和on_entry。</li>
<li>next时None，不会执行on_exit和on_entry。</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">[state]...Entering Init by InitEvent
[state]...Leaving Init by none
[state]...Entering State1 by none
&gt; Send Event1
[guard] Guard1 -&gt; true from State1 to State1 by Event1
[state]...Leaving State1 by Event1
[action] Do Action1 from State1 to State1 by Event1
[state]...Entering State1 by Event1
&gt; Send Event2
[guard] GTrue -&gt; true from State1 to State1 by Event2
[action] Do Action2 from State1 to State1 by Event2
</code></pre></td></tr></table>
</div>
</div><h2 id="exception">exception</h2>
<p>状态机的on_entry, on_exit, Action, Guard都可能抛出异常，不自己处理的话，程序会异常退出。可以通过自己定义exception_caught方法来自定义异常处理。
另外我们可以重载no_transition的方法来处理没有对应状态转移规则的情况。
例如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">exception_caught</span> <span class="p">(</span><span class="n">Event</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">evt</span><span class="p">,</span> <span class="n">Fsm</span><span class="o">&amp;</span> <span class="n">fsm</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;catch exception &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; while &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">evt</span><span class="p">)</span>
        <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">Event</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fsm</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">no_transition</span><span class="p">(</span><span class="n">Event</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">evt</span><span class="p">,</span> <span class="n">Fsm</span> <span class="o">&amp;</span><span class="n">fsm</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;No transition item for &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">x</span>
        <span class="o">&lt;&lt;</span> <span class="s">&#34; while &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">get_typename</span><span class="p">(</span><span class="n">evt</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>针对产生异常的不同时机，其表现有所不同。我们通过一个out_of_range的异常来看一下实际结果。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="nf">sth_wrong</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">a</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">struct</span> <span class="nc">ExceptionOnEntry</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="nf">prepare</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">sth_wrong</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">ExceptionOnExit</span> <span class="o">:</span> <span class="n">BaseState</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="nf">clean</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">sth_wrong</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">ExceptionAction</span> <span class="o">:</span> <span class="n">BaseAction</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">sth_wrong</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">ExceptionGuard</span> <span class="o">:</span> <span class="n">BaseGuard</span> <span class="p">{</span>
    <span class="kt">bool</span> <span class="nf">execute</span><span class="p">(</span><span class="n">Context</span> <span class="o">&amp;</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span>
        <span class="n">sth_wrong</span><span class="p">();</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
    <span class="c1">// ---Transition Table
</span><span class="c1"></span><span class="k">struct</span> <span class="nc">transition_table</span> <span class="o">:</span> <span class="n">boost</span><span class="o">::</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span>
    <span class="c1">//   Start * Event * Next  * Action * Guard
</span><span class="c1"></span>    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">Init</span><span class="p">,</span>   <span class="n">None</span><span class="p">,</span>   <span class="n">State1</span><span class="p">,</span> <span class="n">None</span><span class="p">,</span>    <span class="n">None</span>   <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event1</span><span class="p">,</span> <span class="n">ExceptionOnEntry</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">GTrue</span>  <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event2</span><span class="p">,</span> <span class="n">State2</span><span class="p">,</span> <span class="n">ExceptionAction</span><span class="p">,</span> <span class="n">GTrue</span> <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event3</span><span class="p">,</span> <span class="n">State2</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">ExceptionGuard</span> <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Event4</span><span class="p">,</span> <span class="n">ExceptionOnExit</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">GTrue</span> <span class="o">&gt;</span><span class="p">,</span>
    <span class="n">Row</span><span class="o">&lt;</span> <span class="n">ExceptionOnExit</span><span class="p">,</span> <span class="n">Event5</span><span class="p">,</span> <span class="n">State1</span><span class="p">,</span> <span class="n">Action1</span><span class="p">,</span> <span class="n">GTrue</span> <span class="o">&gt;</span>
<span class="o">&gt;</span> <span class="p">{};</span>
</code></pre></td></tr></table>
</div>
</div><p>运行结果</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">[state]...Entering Init by InitEvent
[state]...Leaving Init by none
[state]...Entering State1 by none
&gt; Send Event1
[guard] GTrue -&gt; true from State1 to ExceptionOnEntry by Event1
[state]...Leaving State1 by Event1
[action] Do Action1 from State1 to ExceptionOnEntry by Event1
[state]...Entering ExceptionOnEntry by Event1
catch exception vector::_M_range_check: __n (which is 2) &gt;= this-&gt;size() (which is 1) while Event1
&gt; Send Event2
[guard] GTrue -&gt; true from State1 to State2 by Event2
[state]...Leaving State1 by Event2
[action] Do ExceptionAction from State1 to State2 by Event2
catch exception vector::_M_range_check: __n (which is 2) &gt;= this-&gt;size() (which is 1) while Event2
&gt; Send Event3
catch exception vector::_M_range_check: __n (which is 2) &gt;= this-&gt;size() (which is 1) while Event3
&gt; Send Event4
[guard] GTrue -&gt; true from State1 to ExceptionOnExit by Event4
[state]...Leaving State1 by Event4
[action] Do Action1 from State1 to ExceptionOnExit by Event4
[state]...Entering ExceptionOnExit by Event4
&gt; Send Event5
[guard] GTrue -&gt; true from ExceptionOnExit to State1 by Event5
[state]...Leaving ExceptionOnExit by Event5
catch exception vector::_M_range_check: __n (which is 2) &gt;= this-&gt;size() (which is 1) while Event5
&gt; Send Event1
No transition item for 2 while Event1
</code></pre></td></tr></table>
</div>
</div><p>可以总结：
一次状态迁移的过程分为guard-&gt;on_exit-&gt;action-&gt;on_entry。其中某一步抛出异常时，状态都会回到sourceState。</p>

    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">Author</span>
    <span class="item-content">lclei</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">LastMod</span>
    <span class="item-content">
        2022-07-10
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/cpp/">cpp</a>
          <a href="/tags/boost/">boost</a>
          </div>
      <nav class="post-nav">
        
        <a class="next" href="/post/hugo_and_git_submodule/">
            <span class="next-text nav-default">Hugo and git submodule</span>
            <span class="next-text nav-mobile">Next</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:lclei@mail.ustc.edu.cn" class="iconfont icon-email" title="email"></a>
      <a href="https://gitee.com/lclei" class="iconfont icon-gitee" title="gitee"></a>
      <a href="https://gitee.com/lclei" class="iconfont icon-github" title="github"></a>
  <a href="http://localhost:1313/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>

<div class="copyright">
  <span class="power-by">
    Powered by <a class="hexo-link" href="https://gohugo.io">Hugo</a>
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    Theme - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  

  <span class="copyright-year">
    &copy; 
    2018 - 
    2022<span class="heart"><i class="iconfont icon-heart"></i></span><span>lclei</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.c12618f9a600c40bd024996677e951e64d3487006775aeb22e200c990006c5c7.js"></script>








</body>
</html>
